#include "EventManager.h"
#include <iostream>
#include "utils\Log.h"

namespace ds {

const uint32 MAX_EB_SIZE = 4096;
// ----------------------------------------------
// Event Buffer implementation
// ----------------------------------------------
EventBuffer::EventBuffer() : m_Index(0), m_Total(0) {
	m_Buffer = new char[MAX_EB_SIZE];
}

EventBuffer::~EventBuffer() {
	delete m_Buffer;
}

void EventBuffer::reset() {
	m_Index = 0;
	m_Total = 0;
}

void EventBuffer::add(EventID id) {
	// write header
	//LOG(logINFO) << "adding empty event at " << m_Index;
	Header h;
	h.id = id;
	h.index = m_Index;
	h.size = 0;
	write(&h, sizeof (Header));
	++m_Total;
	//LOG(logINFO) << "Total " << m_Total;
}

void EventBuffer::add(EventID id, const void* p, size_t size) {
	// write header
	//LOG(logINFO) << "adding event at " << m_Index;
	Header h;
	h.id = id;
	h.index = m_Index;
	h.size = size;
	write(&h, sizeof (Header));
	write(p, size);
	++m_Total;
	//LOG(logINFO) << "Total " << m_Total;
}

void EventBuffer::write(const void* p, size_t size) {
	char *ptr = (char *) p;
	size_t to_write = size;
	char* buffer = (m_Buffer + m_Index);
	m_Index += to_write;
	while (to_write > 0) {
		*buffer = *ptr;
		to_write--;
		ptr++;
		++buffer;
	}
}

size_t EventBuffer::getByID(void *p, size_t size, EventID id) {
	uint32 cnt = 0;
	uint32 ret = 0;
	uint32 index = getIndex(id);
	Header h;
	read(&h, sizeof (Header), index);        
	ret = h.id;
	return read(p,size,index+sizeof(Header));
}

size_t EventBuffer::get(void *p, size_t size, uint32 index) {
	uint32 cnt = 0;
	uint32 ret = 0;
	Header h;
	for (uint32 idx = 0; idx < (index + 1); ++idx) {        
		read(&h, sizeof (Header), cnt);        
		ret = h.id;
		cnt += sizeof (Header) + h.size;
	}
	// we should have the header now
	cnt -= h.size;
	return read(p,size,cnt);
}

bool EventBuffer::containsID(EventID id) {
	for ( int i = 0; i < size(); ++i ) {
		if ( id == getID(i) ) {
			return true;
		}
	}
	return false;
}

uint32 EventBuffer::getIndex(EventID id) {
	uint32 cnt = 0;
	uint32 ret = 0;
	Header h;
	for (uint32 idx = 0; idx < size(); ++idx) {		
		read(&h, sizeof (Header), cnt);
		if ( h.id == id ) {
			ret = h.index;
		}
		cnt += sizeof (Header) + h.size;
	}
	return ret;
}

EventID EventBuffer::getID(uint32 index) {
	uint32 cnt = 0;
	EventID ret = 0;
	for (uint32 idx = 0; idx < (index + 1); ++idx) {
		Header h;
		read(&h, sizeof (Header), cnt);
		ret = h.id;
		cnt += sizeof (Header) + h.size;
	}
	return ret;
}

size_t EventBuffer::read(void *p, size_t size, uint32 index) {
	char *ptr = (char *) p;
	int to_read;
	to_read = size;
	assert( index < MAX_EB_SIZE);
	char* buffer = (m_Buffer + index);
	while (to_read > 0) {
		*ptr = *buffer;
		to_read--;
		ptr++;
		++buffer;
	}
	return (to_read / size);
}

// ----------------------------------------------
//
// ----------------------------------------------
void EventManager::registerEventHandler(EventHandler *handler) {
    handlerList.push_back(handler);
}

void EventManager::processBuffer() {	
	if ( m_Buffer->size() > 0 ) {	
		//LOG(logINFO) << "Firing all events - size: " << m_Buffer->size();	
		std::list<EventHandler*>::iterator it;
		for(it = handlerList.begin(); it != handlerList.end(); ++it) {
			(*it)->process(*m_Buffer);
		}
	}
}

void EventManager::fireEvent(uint32 id,const void* p, size_t size) {
	LOG(logINFO) << "received event - id: " << id;
	m_Buffer->add(id,p,size);
}

void EventManager::fireEvent(EventID id) {
	LOG(logINFO) << "received event - id: " << id;
	m_Buffer->add(id);
}

};
